package cn.iocoder.yudao.module.infra.util.file;

import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.file.FileUtils;
import cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.infra.util.file.vo.FileUploadVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;

@Slf4j
@Component
public class FileUploadUtils {

    /**
     * 文件上传路径
     */
    @Value("${zhima.upload-path:/tmp/llm/uploads/}")
    private String uploadPath;
    @Value("${zhima.image-prefix-url:}")
    public String imagePrefixUrl;

    public FileUploadVo upload(MultipartFile[] files,
                               Integer uploadFileMaxNum,
                               Long uploadFileMaxSize) {

        FileUploadVo fileUploadVo = new FileUploadVo();

        try {
            // 1. 参数校验
            if (files == null || files.length == 0) {
                throw exception(ErrorCodeConstants.UPLOAD_FILE_IS_EMPTY);
            }

            if (files.length > uploadFileMaxNum) {
                throw exception(ErrorCodeConstants.UPLOAD_FILE_TOO_MANY.getCode(),
                        String.format(ErrorCodeConstants.UPLOAD_FILE_TOO_MANY.getMsg(), uploadFileMaxNum));
            }

            for (int i = 0; i < files.length; i++) {
                MultipartFile file = files[i];
                if (file.isEmpty()) {
                    throw exception(ErrorCodeConstants.UPLOAD_FILE_CONTENT_IS_EMPTY.getCode(),
                            String.format(ErrorCodeConstants.UPLOAD_FILE_CONTENT_IS_EMPTY.getMsg(), i + 1));
                }
                String originalFilename = file.getOriginalFilename();
                String extension = FileUtils.getFileExtension(originalFilename);
                // 验证是否为图片文件
                if (!FileUtils.isImageFile(extension)) {
                    throw exception(ErrorCodeConstants.UPLOAD_FILE_ONLY_SUPPORT_IMAGE.getCode(),
                            String.format(ErrorCodeConstants.UPLOAD_FILE_ONLY_SUPPORT_IMAGE.getMsg(), originalFilename));
                }
                // 验证文件大小
                if (file.getSize() > uploadFileMaxSize) {
                    throw exception(ErrorCodeConstants.UPLOAD_FILE_TOO_LARGE.getCode(),
                            String.format(ErrorCodeConstants.UPLOAD_FILE_TOO_LARGE.getMsg(), uploadFileMaxSize, originalFilename));
                }
            }

            // 2. 确保上传目录存在
            String yearMonthDayPath = DateUtils.generateDirectoryPath();
            Path uploadDir = Paths.get(uploadPath + yearMonthDayPath);
            if (!Files.exists(uploadDir)) {
                Files.createDirectories(uploadDir);
            }

            // 3. 逐个处理文件
            for (MultipartFile file : files) {
                // 文件信息提取
                String originalFilename = file.getOriginalFilename();
                String extension = FileUtils.getFileExtension(originalFilename);

                // 生成本地存储文件名
                String storedFilename = UUID.randomUUID() + extension;

                // 保存文件到本地
                Path filePath = uploadDir.resolve(storedFilename);
                Files.copy(file.getInputStream(), filePath);
                fileUploadVo.savedFilePaths.add(filePath.toString());
                fileUploadVo.fileUrls.add(yearMonthDayPath + "/" + storedFilename);

                log.info("文件保存成功：原文件名={}, 本地路径={}, 大小={}KB",
                        originalFilename, filePath, file.getSize() / 1024);
            }

            if (fileUploadVo.savedFilePaths.isEmpty()) {
                throw exception(ErrorCodeConstants.UPLOAD_FILE_ALL_EMPTY);
            }

        } catch (IOException e) {
            log.error("文件上传失败：{}", e.getMessage(), e);
            throw new RuntimeException("文件上传失败：" + e.getMessage());
        }

        return fileUploadVo;
    }

}
